Insights - Tabela de Dados da Aeronaútica

Introdução

A ideia desse documento é pegar um dataset com qual não tenho familiaridade e tentar extrair algum tipo de insight ou algum fato interessante usando R, usando especialmente data.table, Rmarkdown para compilar um documento de como fui me mergulhando nos dados junto com alguns htmlwidgets no caminho, e possivelmente criar um demo de um aplicativo shiny no final.

Nesse caso, escolhi um dataset que me interessou sobre Ocorrências Aeronáuticas na Aviação Civil Brasileira. Imagino que terá como mexer um pouco com mapas usando Leatlet ou alguma outra direção que quisermos tomar.

Esses datasets são extraídos da CENIPA e estão disponíveis no site de dados abertos do Governo Federal.

Segue uma breve descrição do que está no site:

A base de dados de ocorrências aeronáuticas é gerenciada pelo Centro de Investigação e Prevenção de Acidentes Aeronáuticos (CENIPA). Constam nesta base de dados as ocorrências aeronáuticas notificadas ao CENIPA nos últimos 10 anos e que ocorreram em solo brasileiro.

Dentre as informações disponíveis estão os dados sobre as aeronaves envolvidas, fatalidades, local, data, horário dos eventos e informações taxonômicas típicas das investigações de acidentes (AIG). São resguardadas a privacidade de pessoas físicas/jurídicas envolvidas conforme previsto pela Lei de Acesso à Informação (Lei n° 12.527, de 18 de novembro de 2011).

  • Informações dos dados utilizados nesse relatório:
Campo Valor
Fonte http://www.fab.mil.br/cenipa/
Autor Centro de Investigação e Prevenção de Acidentes Aeronáuticos
Mantenedor Centro de Investigação e Prevenção de Acidentes Aeronáuticos
Versão 1.3
Última Atualização 5 de Outubro de 2021, 19:19 (UTC-03:00)
Criado 1 de Junho de 2015, 15:37 (UTC-03:00)
Cobertura geográfica Brasil
Cobertura temporal 2010 a 2019
Fale Conosco
Frequência de atualização Anual
Granularidade geográfica Aeródromo
Granularidade temporal Hora:Minuto
VCGE Aeronáutica [http://vocab.e.gov.br/2011/03/vcge#aeronautica], Transporte Aéreo [http://vocab.e.gov.br/2011/03/vcge#transporte-aereo]

Importação e Tratamentos Iniciais dos Dados

Importação dos Dados

Bom, iniciei o programa importando as informações do portal da CENIPA (Centro de Investigação e Prevenção de Acidentes Aeronáuticos) encontrados no link mencionados na Introdução.

Note que se importarmos o programa sem especificar o encoding como “UTF-8”, então caracteres especiais do Português Brasil serão lidos incorretamente. e.g. “ã”, “é”, “Ç”, etc.

Cruzamento dos Dados

Explicação

Normalmente, essa seria um bom momento de dar uma olhada em algumas colunas e ver o que podemos fazer com elas. No entanto, lendo as informações no site de dados do Governo Federal, notei que apesar de termos 5 tabelas diferentes, há uma tabela “central” que possui informações adicionais distribuídas nas outras 4, assim como na imagem a seguir:

Relacionamento de dados das tabelas que usaremos Como as tabelas são bem pequenas, com menos 10 mil linhas e 30 colunas, cruzá-las e trazer todas as informações em um único dataset poderá facilitar o tratamento de dados mais para frente. Talvez fique um pouco mais difícil de ter uma panorama geral só batendo o olho, mas dado o número colunas parece ser algo tolerável.

Como estou usando o pacote data.table, utilizarei-o para cruzar as informações baseado na chave seguindo a imagem do relacionamento de dados das tabelas acima. Extraindo as informações da imagem acima, seria algo assim:

Cruzamento

Achados sobre a chave

Primeira coisa, dei um head para ter um panorama geral da tabela central, ocorrencia - especialmente das chaves. Nunca se sabe se algo deu errado.

head(ocorrencia[, c("codigo_ocorrencia", "codigo_ocorrencia1", "codigo_ocorrencia2", "codigo_ocorrencia3", "codigo_ocorrencia4")])
##    codigo_ocorrencia codigo_ocorrencia1 codigo_ocorrencia2 codigo_ocorrencia3 codigo_ocorrencia4
## 1:             52242              52242              52242              52242              52242
## 2:             45331              45331              45331              45331              45331
## 3:             45333              45333              45333              45333              45333
## 4:             45401              45401              45401              45401              45401
## 5:             45407              45407              45407              45407              45407
## 6:             52243              52243              52243              52243              52243

Opa! Olhando o header, parece que ocorreu algo peculiar. As 5 primeiras linhas das 5 chaves possuem o valor idêntico!

Note que isso não significa que todas as linhas serão iguais. Porém, há uma leve suspeita para saber se isso é muito mais que uma mera coincidência, ou seja, que realmente esteja assim na tabela inteira.

Para checarmos no R se as colunas possuem valores iguais, podemos usar a função identical para saber se os elementos são iguais.

identical(
  ocorrencia[, codigo_ocorrencia], 
  ocorrencia[, codigo_ocorrencia1], 
  ocorrencia[, codigo_ocorrencia2],
  ocorrencia[, codigo_ocorrencia3],
  ocorrencia[, codigo_ocorrencia4]
)
## [1] TRUE

E olha só! As colunas são de fato idênticas! Pode ser que um dia essas colunas sejam diferentes por algum motivo no site, mas no momento de nossa análise elas são idênticas.

Isso não mudará muita coisa no nosso cruzamento, mas isso significa que podemos descartar alguns dados mais para frente após o cruzamento.

Cruzando as tabelas

Voltando ao que interessa, vamos para o cruzamento. Tentarei fazer 4 left joins seguidos trazendo as informações das 4 tabelas complementares para a tabela central, ocorrencia:

cruzamento1 <- ocorrencia[ocorrencia_tipo, on = "codigo_ocorrencia1"] # Left Join 1
cruzamento2 <- cruzamento1[aeronave, on = "codigo_ocorrencia2"] # Left Join 2
cruzamento3 <- cruzamento2[fator_contribuinte, on = "codigo_ocorrencia3"] # Left Join 3
# tabela <- cruzamento3[recomendacao, on = "codigo_ocorrencia4"] # Left Join 4

Rodando o código acima sem a última linha estar comentada, obtive um erro vindo do último cruzamento, um left join entre ocorrencia e recomendacao:

Error in vecseq(f__, len, if (allow.cartesian || notjoin || !anyDuplicated(f, : Join results in 11387 rows; more than 6687 = nrow(x)+nrow(i). Check for duplicate key values in i each of which join to the same group in x over and over again. If that’s ok, try by=.EACHI to run j for each group to avoid the large allocation. If you are sure you wish to proceed, rerun with allow.cartesian=TRUE. Otherwise, please search for this error message in the FAQ, Wiki, Stack Overflow and data.table issue tracker for advice.

Será que são chaves mesmo?

Aparentemente as chaves de alguma das duas tabelas não são únicas. Vamos dar uma olhadinha na frequências das chaves (código de ocorrência - codigo_ocorrencia) das tabelas:

head(ocorrencia[, .(n = .N), by = codigo_ocorrencia][n > 1][order(-n)])
## Empty data.table (0 rows and 2 cols): codigo_ocorrencia,n
head(ocorrencia_tipo[, .(n = .N), by = codigo_ocorrencia1][n > 1][order(-n)])
##    codigo_ocorrencia1 n
## 1:              66444 3
## 2:              78780 3
## 3:              78879 3
## 4:              78904 3
## 5:              79620 3
## 6:              79651 3
head(aeronave[, .(n = .N), by = codigo_ocorrencia2][n > 1][order(-n)])
##    codigo_ocorrencia2 n
## 1:              45689 3
## 2:              78249 3
## 3:              79441 3
## 4:              45903 2
## 5:              46255 2
## 6:              47245 2
head(fator_contribuinte[, .(n = .N), by = codigo_ocorrencia3][n > 1][order(-n)])
##    codigo_ocorrencia3  n
## 1:              53340 17
## 2:              52265 16
## 3:              45331 15
## 4:              53358 15
## 5:              53488 15
## 6:              45820 14
head(recomendacao[, .(n = .N), by = codigo_ocorrencia4][n > 1][order(-n)])
##    codigo_ocorrencia4  n
## 1:              52265 13
## 2:              66432 12
## 3:              47938 11
## 4:              45571  9
## 5:              46583  9
## 6:              77678  9

Bom, dado que não há uma chave comum entre as tabelas que não estejam duplicadas, não é possível fazer um join simples entre elas como eu gostaria de ter feito. No entanto, como as tabelas não possuem nenhum campo de valor que poderíamos agregar (exceto 3 colunas que contém o nome “total” de frequência, mas que podem ser recalculadas usando as variáveis de origem), é possível fazer algo ainda que nos ajude a colocar tudo numa tabela só, usando cruzamento cartesiano (cartesian join).

Cruzamento Cartesiano

Fazer isso fará com que a tabela após os cruzamentos deixe de ter uma única chave, mas dado que irei sumarizar ela posteriormente com apenas uma seleção das colunas, deve dar tudo certo.

Então, para fazer o cruzamento cartesiano no data.table basta especificar o argumento no final. Vamos ver se agora dará certo…

cruzamento1 <- ocorrencia_tipo[ocorrencia, on = "codigo_ocorrencia1", allow.cartesian = TRUE] # Left Join 1
cruzamento2 <- aeronave[cruzamento1, on = "codigo_ocorrencia2", allow.cartesian = TRUE] # Left Join 2
cruzamento3 <- fator_contribuinte[cruzamento2, on = "codigo_ocorrencia3", allow.cartesian = TRUE] # Left Join 3
tabela <- recomendacao[cruzamento3, on = "codigo_ocorrencia4", allow.cartesian = TRUE] # Left Join 4

head(tabela)
##    codigo_ocorrencia4    recomendacao_numero recomendacao_dia_assinatura recomendacao_dia_encaminhamento recomendacao_dia_feedback                                                                                                                                                                                                                                                                                                                                                                                                                                                            recomendacao_conteudo recomendacao_status recomendacao_destinatario_sigla                recomendacao_destinatario codigo_ocorrencia3            fator_nome            fator_aspecto  fator_condicionante        fator_area codigo_ocorrencia2 aeronave_matricula aeronave_operador_categoria aeronave_tipo_veiculo     aeronave_fabricante aeronave_modelo aeronave_tipo_icao aeronave_motor_tipo aeronave_motor_quantidade
## 1:              52242                   <NA>                        <NA>                            <NA>                      <NA>                                                                                                                                                                                                                                                                                                                                                                                                                                                                             <NA>                <NA>                            <NA>                                     <NA>              52242                  <NA>                     <NA>                 <NA>              <NA>              52242              PRCDL                  PARTICULAR                 AVIÃO       RAYTHEON AIRCRAFT              58               BE58              PISTÃO                   BIMOTOR
## 2:              45331 A-582/CENIPA/2014 - 01                  2016-07-29                      2016-08-25                2016-12-20 Atuar junto às empresas que operam segundo o RBAC 121 de forma tal que assegure que o treinamento de Corporate Ressource Management (CRM) esteja adequado a realidade daquela empresa, que seja constantemente avaliado e reforçado (com a participação da alta direção), envolva todos os profissionais da instituição, que garanta a integração dos diferentes setores da empresa (corporate), e que, acima de tudo, faça parte da cultura de segurança de voo da organização.            CUMPRIDA                            ANAC        AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL              45331 APLICAÇÃO DE COMANDOS DESEMPENHO DO SER HUMANO OPERAÇÃO DA AERONAVE FATOR OPERACIONAL              45331              PRTKB                         ***                 AVIÃO AEROSPATIALE AND ALENIA      ATR-42-500               AT45          TURBOÉLICE                   BIMOTOR
## 3:              45331 A-582/CENIPA/2014 - 02                  2016-07-29                      2016-08-25                2016-12-20                                                                      Atuar junto à Administração do Aeroporto Internacional de Guarulhos, de forma que este passe a ministrar treinamento teórico e prático de atendimento às vítimas de acidentes envolvendo os principais tipos de aeronaves que operam naquela localidade, principalmente os das Linhas Aéreas Regulares, com especial ênfase ao “Layout” e aos meios de remoção de passageiros do interior destas aeronaves.            CUMPRIDA                            ANAC        AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL              45331 APLICAÇÃO DE COMANDOS DESEMPENHO DO SER HUMANO OPERAÇÃO DA AERONAVE FATOR OPERACIONAL              45331              PRTKB                         ***                 AVIÃO AEROSPATIALE AND ALENIA      ATR-42-500               AT45          TURBOÉLICE                   BIMOTOR
## 4:              45331 A-582/CENIPA/2014 - 03                  2016-07-29                      2016-08-25                      NULL                                                                                                                                                                                                                                                                                           Orientar as suas organizações subordinadas em relação ao fiel cumprimento do estabelecido na ICA 100-37, de 28ABR2014, no seu item 5.9.3 e na MCA 100-16, de 18NOV2013, no item 2.3.3. AGUARDANDO RESPOSTA                           DECEA DEPARTAMENTO DE CONTROLE DE ESPAÇO AÉREO              45331 APLICAÇÃO DE COMANDOS DESEMPENHO DO SER HUMANO OPERAÇÃO DA AERONAVE FATOR OPERACIONAL              45331              PRTKB                         ***                 AVIÃO AEROSPATIALE AND ALENIA      ATR-42-500               AT45          TURBOÉLICE                   BIMOTOR
## 5:              45331 A-582/CENIPA/2014 - 01                  2016-07-29                      2016-08-25                2016-12-20 Atuar junto às empresas que operam segundo o RBAC 121 de forma tal que assegure que o treinamento de Corporate Ressource Management (CRM) esteja adequado a realidade daquela empresa, que seja constantemente avaliado e reforçado (com a participação da alta direção), envolva todos os profissionais da instituição, que garanta a integração dos diferentes setores da empresa (corporate), e que, acima de tudo, faça parte da cultura de segurança de voo da organização.            CUMPRIDA                            ANAC        AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL              45331               ATENÇÃO      ASPECTO PSICOLÓGICO           INDIVIDUAL      FATOR HUMANO              45331              PRTKB                         ***                 AVIÃO AEROSPATIALE AND ALENIA      ATR-42-500               AT45          TURBOÉLICE                   BIMOTOR
## 6:              45331 A-582/CENIPA/2014 - 02                  2016-07-29                      2016-08-25                2016-12-20                                                                      Atuar junto à Administração do Aeroporto Internacional de Guarulhos, de forma que este passe a ministrar treinamento teórico e prático de atendimento às vítimas de acidentes envolvendo os principais tipos de aeronaves que operam naquela localidade, principalmente os das Linhas Aéreas Regulares, com especial ênfase ao “Layout” e aos meios de remoção de passageiros do interior destas aeronaves.            CUMPRIDA                            ANAC        AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL              45331               ATENÇÃO      ASPECTO PSICOLÓGICO           INDIVIDUAL      FATOR HUMANO              45331              PRTKB                         ***                 AVIÃO AEROSPATIALE AND ALENIA      ATR-42-500               AT45          TURBOÉLICE                   BIMOTOR
##    aeronave_pmd aeronave_pmd_categoria aeronave_assentos aeronave_ano_fabricacao aeronave_pais_fabricante aeronave_pais_registro aeronave_registro_categoria aeronave_registro_segmento aeronave_voo_origem aeronave_voo_destino aeronave_fase_operacao aeronave_tipo_operacao aeronave_nivel_dano aeronave_fatalidades_total codigo_ocorrencia1    ocorrencia_tipo                                            ocorrencia_tipo_categoria taxonomia_tipo_icao codigo_ocorrencia ocorrencia_classificacao ocorrencia_latitude ocorrencia_longitude ocorrencia_cidade ocorrencia_uf ocorrencia_pais ocorrencia_aerodromo ocorrencia_dia ocorrencia_hora investigacao_aeronave_liberada investigacao_status divulgacao_relatorio_numero divulgacao_relatorio_publicado divulgacao_dia_publicacao total_recomendacoes total_aeronaves_envolvidas ocorrencia_saida_pista
## 1:         2495                   2495                 6                    2003                   BRASIL                 BRASIL                       AVIÃO                 PARTICULAR   FORA DE AERODROMO    FORA DE AERODROMO                  POUSO                PRIVADA                LEVE                          0              52242    ESTOURO DE PNEU FALHA OU MAU FUNCIONAMENTO DE SISTEMA / COMPONENTE | ESTOURO DE PNEU              SCF-NP             52242                INCIDENTE                                               PORTO ALEGRE            RS          BRASIL                 SBPA     05/01/2012        20:27:00                            ***          FINALIZADA                         ***                            NÃO                      NULL                   0                          1                    NÃO
## 2:        18600                  18600                50                    2001                   BRASIL                 BRASIL                       AVIÃO                    REGULAR   FORA DE AERODROMO    FORA DE AERODROMO                DESCIDA                REGULAR              NENHUM                          0              45331 COM PESSOAL EM VOO                                          OUTROS | COM PESSOAL EM VOO                OTHR             45331                 ACIDENTE      -23.4355555556       -46.4730555556         GUARULHOS            SP          BRASIL                 SBGR     06/01/2012        13:44:00                            SIM          FINALIZADA           A-582/CENIPA/2014                            SIM                2016-09-01                   3                          1                    NÃO
## 3:        18600                  18600                50                    2001                   BRASIL                 BRASIL                       AVIÃO                    REGULAR   FORA DE AERODROMO    FORA DE AERODROMO                DESCIDA                REGULAR              NENHUM                          0              45331 COM PESSOAL EM VOO                                          OUTROS | COM PESSOAL EM VOO                OTHR             45331                 ACIDENTE      -23.4355555556       -46.4730555556         GUARULHOS            SP          BRASIL                 SBGR     06/01/2012        13:44:00                            SIM          FINALIZADA           A-582/CENIPA/2014                            SIM                2016-09-01                   3                          1                    NÃO
## 4:        18600                  18600                50                    2001                   BRASIL                 BRASIL                       AVIÃO                    REGULAR   FORA DE AERODROMO    FORA DE AERODROMO                DESCIDA                REGULAR              NENHUM                          0              45331 COM PESSOAL EM VOO                                          OUTROS | COM PESSOAL EM VOO                OTHR             45331                 ACIDENTE      -23.4355555556       -46.4730555556         GUARULHOS            SP          BRASIL                 SBGR     06/01/2012        13:44:00                            SIM          FINALIZADA           A-582/CENIPA/2014                            SIM                2016-09-01                   3                          1                    NÃO
## 5:        18600                  18600                50                    2001                   BRASIL                 BRASIL                       AVIÃO                    REGULAR   FORA DE AERODROMO    FORA DE AERODROMO                DESCIDA                REGULAR              NENHUM                          0              45331 COM PESSOAL EM VOO                                          OUTROS | COM PESSOAL EM VOO                OTHR             45331                 ACIDENTE      -23.4355555556       -46.4730555556         GUARULHOS            SP          BRASIL                 SBGR     06/01/2012        13:44:00                            SIM          FINALIZADA           A-582/CENIPA/2014                            SIM                2016-09-01                   3                          1                    NÃO
## 6:        18600                  18600                50                    2001                   BRASIL                 BRASIL                       AVIÃO                    REGULAR   FORA DE AERODROMO    FORA DE AERODROMO                DESCIDA                REGULAR              NENHUM                          0              45331 COM PESSOAL EM VOO                                          OUTROS | COM PESSOAL EM VOO                OTHR             45331                 ACIDENTE      -23.4355555556       -46.4730555556         GUARULHOS            SP          BRASIL                 SBGR     06/01/2012        13:44:00                            SIM          FINALIZADA           A-582/CENIPA/2014                            SIM                2016-09-01                   3                          1                    NÃO

E sucesso!

Wheeeew.

Agora que tenho uma tabela com todas as informações que preciso, posso criar algumas visões para tirar alguns insights ou análises interessantes sobre. Claro, após tratarmos alguns pontos dela :)

Tratamento dos Dados

Reordenação das Colunas

Para começar os tratamentos dos dados, reordenarei as colunas para ficar na ordem das bases que foram cruzadas, ou seja, na seguinte ordem:

  1. ocorrencia;
  2. ocorrencia_tipo;
  3. aeronave;
  4. fator_contribuinte;
  5. recomendacao;

Lembrando que como as colunas codigo_ocorrencia1, codigo_ocorrencia2, codigo_ocorrencia3, codigo_ocorrencia4 já existiam na tabela “central”, ocorrencia, irei removê-las para evitar algum tipo de mal entendido no vetor.

# Extrai o nome (e a ordem) das colunas pré cruzamento
colunas0 <- names(ocorrencia)
colunas1 <- names(ocorrencia_tipo)[2:length(names(ocorrencia_tipo))] # Eliminando a coluna de codigo_ocorrencia1
colunas2 <- names(aeronave)[2:length(names(aeronave))] # Eliminando a coluna de codigo_ocorrencia2
colunas3 <- names(fator_contribuinte)[2:length(names(fator_contribuinte))] # Eliminando a coluna de codigo_ocorrencia3
colunas4 <- names(recomendacao)[2:length(names(recomendacao))] # Eliminando a coluna de codigo_ocorrencia4

# Concatena os nomes das colunas
ordem_colunas <- c(colunas0, colunas1, colunas2, colunas3, colunas4)

# Atualiza a ordem na tabela por referência
data.table::setcolorder(tabela, ordem_colunas)

Conversão das Colunas

Após a ordenação, posso finalmente começar a dar uma olhada na tabela “analítica” (pós-cruzamento das tabelas) carinhosamente chamada de tabela. Vamos dar uma olhadinha:

str(tabela)
## Classes 'data.table' and 'data.frame':   12167 obs. of  59 variables:
##  $ codigo_ocorrencia              : int  52242 45331 45331 45331 45331 45331 45331 45331 45331 45331 ...
##  $ codigo_ocorrencia1             : int  52242 45331 45331 45331 45331 45331 45331 45331 45331 45331 ...
##  $ codigo_ocorrencia2             : int  52242 45331 45331 45331 45331 45331 45331 45331 45331 45331 ...
##  $ codigo_ocorrencia3             : int  52242 45331 45331 45331 45331 45331 45331 45331 45331 45331 ...
##  $ codigo_ocorrencia4             : int  52242 45331 45331 45331 45331 45331 45331 45331 45331 45331 ...
##  $ ocorrencia_classificacao       : chr  "INCIDENTE" "ACIDENTE" "ACIDENTE" "ACIDENTE" ...
##  $ ocorrencia_latitude            : chr  "" "-23.4355555556" "-23.4355555556" "-23.4355555556" ...
##  $ ocorrencia_longitude           : chr  "" "-46.4730555556" "-46.4730555556" "-46.4730555556" ...
##  $ ocorrencia_cidade              : chr  "PORTO ALEGRE" "GUARULHOS" "GUARULHOS" "GUARULHOS" ...
##  $ ocorrencia_uf                  : chr  "RS" "SP" "SP" "SP" ...
##  $ ocorrencia_pais                : chr  "BRASIL" "BRASIL" "BRASIL" "BRASIL" ...
##  $ ocorrencia_aerodromo           : chr  "SBPA" "SBGR" "SBGR" "SBGR" ...
##  $ ocorrencia_dia                 : chr  "05/01/2012" "06/01/2012" "06/01/2012" "06/01/2012" ...
##  $ ocorrencia_hora                : chr  "20:27:00" "13:44:00" "13:44:00" "13:44:00" ...
##  $ investigacao_aeronave_liberada : chr  "***" "SIM" "SIM" "SIM" ...
##  $ investigacao_status            : chr  "FINALIZADA" "FINALIZADA" "FINALIZADA" "FINALIZADA" ...
##  $ divulgacao_relatorio_numero    : chr  "***" "A-582/CENIPA/2014" "A-582/CENIPA/2014" "A-582/CENIPA/2014" ...
##  $ divulgacao_relatorio_publicado : chr  "NÃO" "SIM" "SIM" "SIM" ...
##  $ divulgacao_dia_publicacao      : chr  "NULL" "2016-09-01" "2016-09-01" "2016-09-01" ...
##  $ total_recomendacoes            : int  0 3 3 3 3 3 3 3 3 3 ...
##  $ total_aeronaves_envolvidas     : int  1 1 1 1 1 1 1 1 1 1 ...
##  $ ocorrencia_saida_pista         : chr  "NÃO" "NÃO" "NÃO" "NÃO" ...
##  $ ocorrencia_tipo                : chr  "ESTOURO DE PNEU" "COM PESSOAL EM VOO" "COM PESSOAL EM VOO" "COM PESSOAL EM VOO" ...
##  $ ocorrencia_tipo_categoria      : chr  "FALHA OU MAU FUNCIONAMENTO DE SISTEMA / COMPONENTE | ESTOURO DE PNEU" "OUTROS | COM PESSOAL EM VOO" "OUTROS | COM PESSOAL EM VOO" "OUTROS | COM PESSOAL EM VOO" ...
##  $ taxonomia_tipo_icao            : chr  "SCF-NP" "OTHR" "OTHR" "OTHR" ...
##  $ aeronave_matricula             : chr  "PRCDL" "PRTKB" "PRTKB" "PRTKB" ...
##  $ aeronave_operador_categoria    : chr  "PARTICULAR" "***" "***" "***" ...
##  $ aeronave_tipo_veiculo          : chr  "AVIÃO" "AVIÃO" "AVIÃO" "AVIÃO" ...
##  $ aeronave_fabricante            : chr  "RAYTHEON AIRCRAFT" "AEROSPATIALE AND ALENIA" "AEROSPATIALE AND ALENIA" "AEROSPATIALE AND ALENIA" ...
##  $ aeronave_modelo                : chr  "58" "ATR-42-500" "ATR-42-500" "ATR-42-500" ...
##  $ aeronave_tipo_icao             : chr  "BE58" "AT45" "AT45" "AT45" ...
##  $ aeronave_motor_tipo            : chr  "PISTÃO" "TURBOÉLICE" "TURBOÉLICE" "TURBOÉLICE" ...
##  $ aeronave_motor_quantidade      : chr  "BIMOTOR" "BIMOTOR" "BIMOTOR" "BIMOTOR" ...
##  $ aeronave_pmd                   : int  2495 18600 18600 18600 18600 18600 18600 18600 18600 18600 ...
##  $ aeronave_pmd_categoria         : int  2495 18600 18600 18600 18600 18600 18600 18600 18600 18600 ...
##  $ aeronave_assentos              : chr  "6" "50" "50" "50" ...
##  $ aeronave_ano_fabricacao        : chr  "2003" "2001" "2001" "2001" ...
##  $ aeronave_pais_fabricante       : chr  "BRASIL" "BRASIL" "BRASIL" "BRASIL" ...
##  $ aeronave_pais_registro         : chr  "BRASIL" "BRASIL" "BRASIL" "BRASIL" ...
##  $ aeronave_registro_categoria    : chr  "AVIÃO" "AVIÃO" "AVIÃO" "AVIÃO" ...
##  $ aeronave_registro_segmento     : chr  "PARTICULAR" "REGULAR" "REGULAR" "REGULAR" ...
##  $ aeronave_voo_origem            : chr  "FORA DE AERODROMO" "FORA DE AERODROMO" "FORA DE AERODROMO" "FORA DE AERODROMO" ...
##  $ aeronave_voo_destino           : chr  "FORA DE AERODROMO" "FORA DE AERODROMO" "FORA DE AERODROMO" "FORA DE AERODROMO" ...
##  $ aeronave_fase_operacao         : chr  "POUSO" "DESCIDA" "DESCIDA" "DESCIDA" ...
##  $ aeronave_tipo_operacao         : chr  "PRIVADA" "REGULAR" "REGULAR" "REGULAR" ...
##  $ aeronave_nivel_dano            : chr  "LEVE" "NENHUM" "NENHUM" "NENHUM" ...
##  $ aeronave_fatalidades_total     : int  0 0 0 0 0 0 0 0 0 0 ...
##  $ fator_nome                     : chr  NA "APLICAÇÃO DE COMANDOS" "APLICAÇÃO DE COMANDOS" "APLICAÇÃO DE COMANDOS" ...
##  $ fator_aspecto                  : chr  NA "DESEMPENHO DO SER HUMANO" "DESEMPENHO DO SER HUMANO" "DESEMPENHO DO SER HUMANO" ...
##  $ fator_condicionante            : chr  NA "OPERAÇÃO DA AERONAVE" "OPERAÇÃO DA AERONAVE" "OPERAÇÃO DA AERONAVE" ...
##  $ fator_area                     : chr  NA "FATOR OPERACIONAL" "FATOR OPERACIONAL" "FATOR OPERACIONAL" ...
##  $ recomendacao_numero            : chr  NA "A-582/CENIPA/2014 - 01" "A-582/CENIPA/2014 - 02" "A-582/CENIPA/2014 - 03" ...
##  $ recomendacao_dia_assinatura    : IDate, format: NA "2016-07-29" "2016-07-29" "2016-07-29" ...
##  $ recomendacao_dia_encaminhamento: IDate, format: NA "2016-08-25" "2016-08-25" "2016-08-25" ...
##  $ recomendacao_dia_feedback      : chr  NA "2016-12-20" "2016-12-20" "NULL" ...
##  $ recomendacao_conteudo          : chr  NA "Atuar junto às empresas que operam segundo o RBAC 121 de forma tal que assegure que o treinamento de Corporate "| __truncated__ "Atuar junto à Administração do Aeroporto Internacional de Guarulhos, de forma que este passe a ministrar treina"| __truncated__ "Orientar as suas organizações subordinadas em relação ao fiel cumprimento do estabelecido na ICA 100-37, de 28A"| __truncated__ ...
##  $ recomendacao_status            : chr  NA "CUMPRIDA" "CUMPRIDA" "AGUARDANDO RESPOSTA" ...
##  $ recomendacao_destinatario_sigla: chr  NA "ANAC" "ANAC" "DECEA" ...
##  $ recomendacao_destinatario      : chr  NA "AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL" "AGÊNCIA NACIONAL DE AVIAÇÃO CIVIL" "DEPARTAMENTO DE CONTROLE DE ESPAÇO AÉREO" ...
##  - attr(*, ".internal.selfref")=<externalptr>

Hmm…

Analisando com calma a tabela, podemos anotar alguns pontos estranhos:

  • De cara, dá para ver algumas colunas que não eram para ser texto: aeronave_ano_fabricacao, ocorrencia_latitude, ocorrencia_dia, etc;
    • Não appenas isso: dentre essas colunas, algumas precisam ser convertidas para número enquanto outras para data;
  • Além disso, nossa tabela possui alguns valores estranhos como “***“,”NULL” (literalmente como texto, não como valor booleano), que irei inferir que são Missing já que não possuo metadados sobre o dataset.

Como os valores missing influenciará na conversão dos dados de texto para outros tipos, então começarei tratando eles primeiro.

Corrigindo os valores missing

Para corrigir os valores missing das colunas que são do tipo Texto, primeiro:

  • Filtramos todas as colunas que são texto;

  • E depois, caso algum elemento se encaixe em alguns dos valores estranhos que vimos, transformamos em missing (NA). e.g. “***“,”NULL”, etc.

Então, temos:

# Seleciona as colunas que são do tipo character (texto), e guarda na colunas_texto
indices_colunas_texto <- which(unlist(lapply(tabela, is.character)))
colunas_texto <- names(tabela)[indices_colunas_texto]

# Para cada coluna do colunas_texto, troca o valor estranho para missing (NA) usando ifelse
tabela[, (colunas_texto) := lapply(.SD, function(x) ifelse(
  x == "***" 
  | x == "****" 
  | x == "*****"
  | x == "******"
  | x == "*******"
  | x == "********"
  | x == "*********"
  | x == "****_***"
  | x == "****_****"
  | x == "NULL" 
  | x == "", 
  NA, x)), .SDcols = colunas_texto]

Texto para datas

As colunas que deveriam ser do tipo Data contém “dia” no nome:

names(tabela)[grepl("*dia", names(tabela))]
## [1] "ocorrencia_dia"                  "divulgacao_dia_publicacao"       "recomendacao_dia_assinatura"     "recomendacao_dia_encaminhamento" "recomendacao_dia_feedback"
de_texto_para_data <- names(tabela)[grepl("*dia", names(tabela))]
str(tabela[, ..de_texto_para_data])
## Classes 'data.table' and 'data.frame':   12167 obs. of  5 variables:
##  $ ocorrencia_dia                 : chr  "05/01/2012" "06/01/2012" "06/01/2012" "06/01/2012" ...
##  $ divulgacao_dia_publicacao      : chr  NA "2016-09-01" "2016-09-01" "2016-09-01" ...
##  $ recomendacao_dia_assinatura    : IDate, format: NA "2016-07-29" "2016-07-29" "2016-07-29" ...
##  $ recomendacao_dia_encaminhamento: IDate, format: NA "2016-08-25" "2016-08-25" "2016-08-25" ...
##  $ recomendacao_dia_feedback      : chr  NA "2016-12-20" "2016-12-20" NA ...
##  - attr(*, ".internal.selfref")=<externalptr>

Logo, para converter, basta aplicarmos o as.IDate - que é essencialmente o Date normal do R, mas compatível com o data.table.

Só um ponto de atenção: a variável ocorrencia_dia não só está como texto quanto também está em um formato de data diferente das demais. Tirando isso, as coisas estão dando tudo certo!

# Converte somente a coluna ocorrencia_dia por ter um formato diferente (DD/MM/YYYY) 
tabela[, ocorrencia_dia := as.IDate(ocorrencia_dia, "%d/%m/%Y")]

# Converte colunas que possuem o formato (YYYY-MM-DD) 
tabela[, `:=`(
  divulgacao_dia_publicacao = as.IDate(divulgacao_dia_publicacao, "%Y-%m-%d"),
  recomendacao_dia_assinatura = as.IDate(recomendacao_dia_assinatura, "%Y-%m-%d"),
  recomendacao_dia_encaminhamento = as.IDate(recomendacao_dia_encaminhamento, "%Y-%m-%d"),
  recomendacao_dia_feedback = as.IDate(recomendacao_dia_feedback, "%Y-%m-%d")
)]

# Converte a coluna ocorrencia_hora para o formato ITime 
tabela[, ocorrencia_hora := as.ITime(ocorrencia_hora, "%d/%m/%Y")]

Texto para numérico/inteiro

Agora para o caso de ver qual variável deveria ser numérica, não tem jeito. Como o número é pequeno, dá para darmos uma olhada olhando no “str(tabela)” acima.

  • ocorrencia_latitude;
  • ocorrencia_longitude;
  • aeronave_assentos;
  • aeronave_ano_fabricacao;

Sabendo quais são as colunas, basta convertê-las:

colunas_texto_para_numero <- c(
"ocorrencia_latitude",
"ocorrencia_longitude",
"aeronave_assentos",
"aeronave_ano_fabricacao"
)

# tabela[, (colunas_texto_para_numero) := lapply(.SD, function(x) as.numeric(x)), .SDcols = colunas_texto_para_numero]

Ou pelo menos deveria ser! Tentando converter as 4 colunas de uma vez retorna erro em 2 colunas - que estão aplicando NA por coercion, ou seja, por não saber converter. Olhando mais afundo, notamos que o problema ocorre nas colunas de latitude e longitude. Portanto, vamos converter as outras duas que deram certo, aeronave_assentos e aeronave_assentos, e ver mais a fundo o caso do da latitude e longitude.

tabela[, `:=`(
  aeronave_assentos = as.numeric(aeronave_assentos),
  aeronave_ano_fabricacao = as.numeric(aeronave_ano_fabricacao)
)]

Latitude e Longitude

Texto

Astericos
# Observações que ainda possuem asteriscos
unique(tabela$ocorrencia_latitude)[grepl("\\*", unique(tabela$ocorrencia_latitude))]
## [1] "-14.71083***"
# Observações que ainda possuem asteriscos
unique(tabela$ocorrencia_longitude)[grepl("\\*", unique(tabela$ocorrencia_longitude))]
## character(0)
Coordenadas em outro sistema (como DMS - Decimal degrees, minutes and seconds)
tabela[ocorrencia_latitude %like% "”", ocorrencia_latitude]
## [1] "15° 39’ 00”S" "15° 39’ 00”S"
tabela[ocorrencia_longitude %like% "”", ocorrencia_longitude]
## [1] "056° 07’ 03” W" "056° 07’ 03” W"
Outros casos peculiares
head(sort(unique(tabela[, ocorrencia_latitude])), 135)
##   [1] "- 22.75944"      "-0,889722"       "-0.0"            "-0.0075"         "-0.050833333333" "-0.0911111111"   "-0.2002777778"   "-0.2827778"      "-0.41694444444"  "-0.8669444444"   "-0.985"          "-0.9880555556"   "-01.43778"       "-01.5325"        "-03.76472"       "-04.1650"        "-04.87139"       "-05.05972222"    "-05.2850"        "-05.530555"      "-07.04028"       "-07.2191666"     "-08.12638"       "-08.126388"      "-08.1263888"     "-08.12638888"    "-08.12639"       "-08.271666"      "-08.713611"      "-08.84917"       "-08.9594444"     "-09.53432276"    "-09.868888"      "-09.96583"       "-1,3708"         "-1,3808"         "-1.0870555555"   "-1.144722"       "-1.1966666667"   "-1.2388888889"   "-1.2941666667"   "-1.326280"       "-1.3611111111"   "-1.38000"        "-1.3801422"      "-1.380277777777" "-1.38472"        "-1.3847222222"   "-1.384722222222" "-1.38556"        "-1.3858333333"   "-1.3916666667"   "-1.3927777778"   "-1.4077777778"   "-1.4119444444"  
##  [56] "-1.415"          "-1.41500"        "-1.4169444444"   "-1.419722222"    "-1.4361111111"   "-1.437777777777" "-1.4452777778"   "-1.46472"        "-1.4886111111"   "-1.532923792"    "-1.5922222222"   "-1.6386111111"   "-1.65000"        "-1.7213888889"   "-1.775"          "-1.797777777777" "-1.9536111111"   "-1.955833"       "-1.9813888889"   "-10.0061111111"  "-10.011389"      "-10.017222222"   "-10.022222"      "-10.058333"      "-10.0672222222"  "-10.081667"      "-10.10806"       "-10.182778"      "-10.183889"      "-10.188187"      "-10.29"          "-10.2900000"     "-10.2916666667"  "-10.2961111111"  "-10.296389"      "-10.3772222222"  "-10.4144444444"  "-10.418333"      "-10.422500"      "-10.4908333333"  "-10.4933333333"  "-10.5261111111"  "-10.5305555556"  "-10.5972222222"  "-10.6002777778"  "-10.656111"      "-10.7297222222"  "-10.7338888889"  "-10.7555555556"  "-10.7641666667"  "-10.7691666667"  "-10.804722"      "-10.870556"      "-10.884167"      "-10.8875"       
## [111] "-10.8883333333"  "-10.9033333333"  "-10.927500"      "-10.94"          "-10.94361"       "-10.9583333333"  "-10.98472"       "-10.9852777778"  "-10.991111"      "-101.827.777.77" "-102.961.111.11" "-103.452.777.77" "-11.009317"      "-11.113611111"   "-11.131111"      "-11.134167"      "-11.2644444444"  "-11.383056"      "-11.41472222"    "-11.4194444444"  "-11.42056"       "-11.4219444444"  "-11.461667"      "-11.4955555556"  "-11.537666"
head(sort(unique(tabela[, ocorrencia_longitude])), 40)
##  [1] "- 40.68583"      "-0.0"            "-18.2250"        "-18.83916"       "-18.973889"      "-20.4230"        "-21.24055"       "-22.92166666666" "-23.18166666666" "-32.9919444444"  "-34.8425"        "-34.85"          "-34.87833333"    "-34.8913888889"  "-34.89138889"    "-34.9005555556"  "-34.91277"       "-34.92277"       "-34.922777"      "-34.92277777"    "-34.922777777"   "-34.9227777777"  "-34.92277777777" "-34.9227777778"  "-34.92277778"    "-34.92278"       "-34.927262"      "-34.95027"       "-34.9502777778"  "-34.9505555555"  "-348.425"        "-348.452.777.77" "-348.913.888.88" "-349.127.777.77" "-349.227.777.77" "-349.502.777.77" "-35.1758333333"  "-35.23"          "-35.24341"       "-35.29166"
tail(sort(unique(tabela[, ocorrencia_longitude])), 55)
##  [1] "\\t-55.93888889\\t" "\\t-55.94583333\\t" "\\t-55.97388889\\t" "\\t-56.04083333\\t" "\\t-56.06472222\\t" "\\t-56.08805556\\t" "\\t-56.26361111\\t" "\\t-56.45194444\\t" "\\t-56.46722222\\t" "\\t-56.51388889\\t" "\\t-56.56222222\\t" "\\t-56.62972222\\t" "\\t-56.74527778\\t" "\\t-56.95916667\\t" "\\t-57.043333\\t"   "\\t-57.16583333\\t" "\\t-57.26611111\\t" "000"                "042.4241"           "056° 07’ 03” W"     "11.8666666667"      "14.98400"           "16,6372222"         "38.5322222222"      "41.06833"           "413.077.777.778"    "43.98916667"        "432.505.555.556"    "439.505.555.556"    "444.216.666.667"    "45.8922222222"      "46.473055555556"    "46.633888888889"    "46.6563888889"      "46.9047222222"      "46.9436111111"      "465.741.666.667"    "466.341.666.667"    "47.0577777778"      "47.9186111111"      "48.022222222222"    "48.5958333333"      "487.575"            "488.166.666.667"    "49.226667"          "49.2286"            "49.3988888889"     
## [48] "49.4686111111"      "493.494.444.444"    "55.6725"            "56.5230555556"      "63.9027777778"      "Longitude: -43."    "Longitude: -47."    "NÃO INFORMADO"

Texto…

Texto 2…

### Caso 1 - Espaço, e.g. "- 22.75944"
tabela[, ocorrencia_latitude := gsub(" ", "", ocorrencia_latitude)]
tabela[, ocorrencia_longitude := gsub(" ", "", ocorrencia_longitude)]

### Caso 2 - Vírgula, e.g. "-0,889722"
tabela[, ocorrencia_latitude := gsub(",", ".", ocorrencia_latitude)]
tabela[, ocorrencia_longitude := gsub(",", ".", ocorrencia_longitude)]

### Caso 3 - Duplo negativo, e.g. "--49.0324242"
tabela[, ocorrencia_latitude := gsub("--", "-", ocorrencia_latitude)]
tabela[, ocorrencia_longitude := gsub("--", "-", ocorrencia_longitude)]

### Caso 4 - Com a palavra Latitude/Longitude na frente, e.g. "Longitude:-47."
tabela[ocorrencia_latitude %like% "Latitude", ocorrencia_latitude := gsub("Latitude:", "", ocorrencia_latitude)]
tabela[ocorrencia_longitude %like% "Longitude", ocorrencia_longitude := gsub("Longitude:", "", ocorrencia_longitude)]

### Caso 5 - Coordenada em DMS - Decimal degrees, minutes and seconds
tabela[ocorrencia_latitude == "15°39’00”S", ocorrencia_latitude := "-15.650000"]
tabela[ocorrencia_longitude == "056°07’03”W", ocorrencia_longitude := "-56.117500"]

### Caso 6 - Asteriscos na frente ou atrás do número (só Lat)
tabela[ocorrencia_latitude == "***-22.98575784", ocorrencia_latitude := "-22.98575784"]
tabela[ocorrencia_latitude == "-14.71083***", ocorrencia_latitude := "-14.71083"]

### Caso 7 - Possui/termina com S, N, W, ou E, mas não está formatado em coordenadas DMS como no Caso 5
tabela[, ocorrencia_latitude := gsub("S", "", ocorrencia_latitude)]
tabela[, ocorrencia_latitude := gsub("N", "", ocorrencia_latitude)]
tabela[, ocorrencia_longitude := gsub("W", "", ocorrencia_longitude)]
tabela[, ocorrencia_longitude := gsub("E", "", ocorrencia_longitude)]

### Caso 8 - Possui/termina com o símbolo de Grau ("º"/"°")
tabela[, ocorrencia_latitude := gsub("°", "", ocorrencia_latitude)]
tabela[, ocorrencia_longitude := gsub("°", "", ocorrencia_longitude)]

tabela_ <- data.table::copy(tabela)

### Caso 9 - Número cheio de separadores usando ponto ("."). (Lat e Log)
# Cria flag marcando casos que possíveis não estão todos corretos
tabela[, flag_lat_long := fifelse(
    lengths(regmatches(ocorrencia_latitude, gregexpr("\\.", ocorrencia_latitude))) > 1
    | lengths(regmatches(ocorrencia_longitude, gregexpr("\\.", ocorrencia_longitude))) > 1,
    FALSE,
    TRUE
  )
]

# Latitude
tabela[
  lengths(regmatches(ocorrencia_latitude, gregexpr("\\.", ocorrencia_latitude))) > 1, 
  ocorrencia_latitude := fifelse(
    as.numeric(gsub("\\.", "", ocorrencia_latitude)) > 0, 
    sub("(.{2})(.*)", "\\1.\\2", gsub("\\.", "", ocorrencia_latitude)), 
    sub("(.{3})(.*)", "\\1.\\2", gsub("\\.", "", ocorrencia_latitude))
  )
]

# Longitude
tabela[
  lengths(regmatches(ocorrencia_longitude, gregexpr("\\.", ocorrencia_longitude))) > 1, 
  ocorrencia_longitude := fifelse(
    as.numeric(gsub("\\.", "", ocorrencia_longitude)) > 0, 
    sub("(.{2})(.*)", "\\1.\\2", gsub("\\.", "", ocorrencia_longitude)), 
    sub("(.{3})(.*)", "\\1.\\2", gsub("\\.", "", ocorrencia_longitude))
  )
]

### Após tratamentos, FINALMENTE converte as colunas para numérico
tabela[, `:=`(
  ocorrencia_latitude = as.numeric(ocorrencia_latitude),
  ocorrencia_longitude = as.numeric(ocorrencia_longitude)
)]
## Warning in eval(jsub, SDenv, parent.frame()): NAs introduzidos por coerção

## Warning in eval(jsub, SDenv, parent.frame()): NAs introduzidos por coerção
### Caso 10 - 44993 e 50794 não possuem longitude
# Como a ocorrencia 44993 foi na cidade do Rio de Janeiro, aproxima usando as coordenadas
# do Aeroporto Doméstico Santos Dumont: -22.90825417333246, -43.16789880589976
tabela[codigo_ocorrencia == 44993, ocorrencia_longitude := -43.16789880589976]

# Como a ocorrencia 50794 foi na cidade de Turmalina, MG, aproxima usando as coordenadas
# do ponto zero da cidade: -17.285824901708047, -42.731887838264434
tabela[codigo_ocorrencia == 50794, ocorrencia_longitude := -42.731887838264434]

Após tratamentos:

head(sort(unique(tabela[, ocorrencia_latitude])), 135)
##   [1] -235.07500 -229.87500 -229.27500 -228.22500 -222.97500 -204.42500 -204.37500 -173.82500 -167.02500 -163.62500 -158.62500 -158.52500 -156.52500  -98.68889  -95.87500  -95.17222  -93.67500  -92.56111  -92.28333  -90.33333  -89.59444  -87.13611  -85.90556  -85.66667  -81.26389  -81.16944  -80.38333  -78.44444  -78.21389  -75.99444  -75.02500  -73.98400  -73.58333  -72.29167  -71.60556  -71.48333  -70.91944  -70.89444  -70.46389  -68.23611  -68.18889  -67.63889  -67.63056  -66.93056  -65.40278  -65.29167  -60.86944  -59.08611  -58.68333  -53.68056  -52.48805  -51.46111  -50.50556  -49.21167  -48.74444  -48.71389  -48.48056  -48.10056  -47.20278  -46.94361  -45.19050  -44.95722  -42.50556  -42.44444  -42.06750  -41.62500  -40.33250  -37.75833  -37.08333  -35.09167  -34.97941  -33.43639  -33.10528  -32.41556  -32.22194  -31.45139  -31.42278  -31.05167  -30.73056  -30.72778  -30.60556  -30.44944  -30.41111  -30.38889  -30.38333  -30.36083  -30.24556  -30.05028  -29.99472  -29.99472
##  [91]  -29.99472  -29.99389  -29.99389  -29.99389  -29.99389  -29.99388  -29.99194  -29.98806  -29.69583  -29.41306  -29.36472  -29.19556  -29.04444  -28.95972  -28.93056  -28.87431  -28.48668  -27.90361  -27.79167  -27.78139  -27.67274  -27.67253  -27.67028  -27.67028  -27.67028  -27.67028  -27.61028  -27.56667  -27.17111  -27.16333  -27.16306  -27.13389  -27.08722  -27.05750  -27.01500  -26.87861  -26.87861  -26.83278  -26.78250  -26.66667  -26.65528  -26.55805  -26.22306  -26.22306  -26.05889
head(sort(unique(tabela[, ocorrencia_longitude])), 40)
##  [1] -6.013827e+10 -4.819457e+08 -6.689750e+02 -6.006250e+02 -5.633750e+02 -5.611750e+02 -5.589250e+02 -5.215750e+02 -4.599750e+02 -4.583750e+02 -4.502250e+02 -4.501250e+02 -4.316250e+02 -3.832250e+02 -3.484250e+02 -7.277972e+01 -7.277972e+01 -7.277972e+01 -7.276944e+01 -7.276944e+01 -7.274528e+01 -7.270556e+01 -7.194694e+01 -7.168833e+01 -7.168833e+01 -7.164860e+01 -7.048278e+01 -7.048278e+01 -7.015194e+01 -7.011417e+01 -7.009389e+01 -7.002528e+01 -6.993778e+01 -6.993778e+01 -6.991694e+01 -6.982333e+01 -6.978000e+01 -6.957167e+01 -6.942361e+01 -6.926639e+01
tail(sort(unique(tabela[, ocorrencia_longitude])), 40)
##  [1] -18.973889 -18.839160 -18.225000  -8.008720  -6.184667  -5.060556   0.000000  11.866667  14.984000  16.637222  38.532222  41.068330  41.307778  42.424100  43.250556  43.950556  43.989167  44.421667  45.892222  46.473056  46.574167  46.633889  46.634167  46.656389  46.904722  46.943611  47.057778  47.918611  48.022222  48.595833  48.816667  49.226667  49.228600  49.349444  49.398889  49.468611  55.672500  56.523056  63.902778 487.575000

Após tratamentos…


Análises

Em construção, maybe

Ocorrências

# Seleciona as colunas relevantes, e dá um distinct para evitar observações duplicadas
ocorrencias_tempo <- unique(tabela[, .(ocorrencia_dia, codigo_ocorrencia, ocorrencia_classificacao)])

#
ocorrencias_tempo[, `:=`(
  ocorrencia_ano = as.character(data.table::year(ocorrencia_dia)),
  ocorrencia_mes = paste0(substr(ocorrencia_dia, 1, 7), "-01"),
  ocorrencia_dia_plot = as.character(ocorrencia_dia),
  ocorrencia_dia_calendario = as.IDate(substr(ocorrencia_dia, 6, 10), format="%m-%d")
)]

Número de ocorrências pelo tempo

Ano e Mês

e_ocorrencias_ano <- ocorrencias_tempo[, .(Ocorrências = .N), keyby = ocorrencia_ano] |>  
  e_charts(ocorrencia_ano, height = 300, elementId = "e_ocorrencias_ano") |>  
  e_title("Número de Ocorrências Aeronaúticas - Ao Ano", left = "center") |> 
  e_legend(bottom = 0) |>
  e_theme("chalk") |>  
  e_line(Ocorrências, name = "Número de Ocorrências") |>  
  e_mark_line("Número de Ocorrências", data = list(type = "average")) |> 
  e_tooltip(trigger = "axis") |> 
  e_labels() |> 
  e_datazoom(show = FALSE)

e_ocorrencias_mes <- ocorrencias_tempo[, .(Ocorrências = .N), keyby = ocorrencia_mes] |>
  e_charts(ocorrencia_mes, height = 300, elementId = "e_ocorrencias_mes") |>
  e_title("Número de Ocorrências Aeronaúticas - Ao Mês", left = "center") |>
  e_legend(show = FALSE) |>
  e_theme("chalk") |>
  e_line(Ocorrências, name = "Número de Ocorrências") |>
  e_mark_line("Número de Ocorrências", data = list(type = "average")) |>
  e_tooltip(trigger = "axis") |>
  e_datazoom() |>
  e_connect("e_ocorrencias_ano")

e_arrange(e_ocorrencias_ano, e_ocorrencias_mes)

Ano e Mês - Por classificação de ocorrência

e_ocorrencias_classif_ano <- ocorrencias_tempo[, .(Ocorrências = .N), keyby = c("ocorrencia_ano", "ocorrencia_classificacao")] |> 
  group_by(ocorrencia_classificacao) |>
  e_charts(ocorrencia_ano, height = 300, elementId = "e_ocorrencias_classif_ano") |>  
  e_title("Número de Ocorrências Aeronaúticas - Ao Ano", left = "center") |> 
  e_legend(bottom = 0) |>
  e_theme("chalk") |>  
  e_line(Ocorrências) |>  
  e_mark_line("Número de Ocorrências", data = list(type = "average")) |> 
  e_tooltip(trigger = "axis") |> 
  e_labels() |> 
  e_datazoom(show = FALSE)

e_ocorrencias_classif_mes <- ocorrencias_tempo[, .(Ocorrências = .N), keyby = c("ocorrencia_mes", "ocorrencia_classificacao")] |>
  group_by(ocorrencia_classificacao) |>
  e_charts(ocorrencia_mes, height = 300, elementId = "e_ocorrencias_classif_mês") |>
  e_title("Número de Ocorrências Aeronaúticas - Ao Mês", left = "center") |>
  e_legend(show = FALSE) |>
  e_theme("chalk") |>
  e_line(Ocorrências) |>
  e_mark_line("Número de Ocorrências", data = list(type = "average")) |>
  e_tooltip(trigger = "axis") |>
  e_datazoom() |>
  e_connect("e_ocorrencias_classif_ano")

e_arrange(e_ocorrencias_classif_ano, e_ocorrencias_classif_mes)

Dia - Calendário

ocorrencias_tempo_dia <- ocorrencias_tempo[, .(N = .N), keyby = ocorrencia_dia_calendario]

ano_tbl_ocorrencias <- year(
  ocorrencias_tempo_dia[!is.na(ocorrencia_dia_calendario)][1, ocorrencia_dia_calendario]
)
min_ocorrencias_dia <- min(ocorrencias_tempo_dia[!is.na(ocorrencia_dia_calendario), N])
max_ocorrencias_dia <- max(ocorrencias_tempo_dia[!is.na(ocorrencia_dia_calendario), N])

ocorrencias_tempo_dia |> 
  e_charts(ocorrencia_dia_calendario)|> 
  e_title("Número de Ocorrências Aeronaúticas - Sumarizado por Dia", top = "1%", left = "center") |>
  e_theme("essos") |>  
  e_calendar(
    range = ano_tbl_ocorrencias,
    # orient = "vertical",
    # width = 1,
    cellSize = 12.5,
    left = "center",
    top = "15%",
    # dayLabel = list(show = F),
    yearLabel = list(show = F)
    ) |> 
  e_heatmap(N, coord_system = "calendar") |> 
  e_visual_map(
    min = min_ocorrencias_dia,
    max = max_ocorrencias_dia,
    type = "piecewise",
    orient = "horizontal",
    left = "center",
    top = "6.75%"
    ) |>  
  e_tooltip(formatter = htmlwidgets::JS("
      function(params){
        return('<strong>Data: </strong>' + params.value[0] + '<br /><strong>Número de Ocorrências: </strong>' + params.value[1])
      }
    ")
  )

Ocorrências pelo tipo

ocorrencias_tipo_plot <- tabela[, .N, keyby = c("ocorrencia_tipo", "ocorrencia_classificacao")]

Top 10 - Ocorrências por Tipo

tail(ocorrencias_tipo_plot[order(N)], 10) |>
  group_by(ocorrencia_classificacao) |>
  e_charts(ocorrencia_tipo) |>
  e_title("Top 10 - Ocorrências por Tipo", left = "center") |>
  e_theme("chalk") |>  
  e_x_axis(axisLabel = list(fontSize = 7)) |>  
  e_legend(bottom = 0) |>  
  e_bar(N, emphasis = list(focus = "self")) |>
  e_tooltip() |>
  e_flip_coords()

Top 10 - Ocorrências por Tipo - Incidente Grave

tail(ocorrencias_tipo_plot[ocorrencia_classificacao == "INCIDENTE GRAVE"][order(N)], 10) |>
  e_charts(ocorrencia_tipo) |>
  e_title("Top 10 - Ocorrências por Tipo - Incidente Grave", left = "center") |>
  e_x_axis(axisLabel = list(fontSize = 7)) |>  
  e_theme("chalk") |>  
  e_legend(bottom = 0) |>  
  e_bar(N, colorBy = "data", emphasis = list(focus = "self")) |>
  e_tooltip() |>
  e_flip_coords()

Mapa das Ocorrências

Em construção

Aeronaves

Em construção

Recomendações

Em construção